/*
*********************************************************************************************************
*                                        uC/OS, The Real-Time Kernel
*
*                                                EXAMPLE #1
*********************************************************************************************************
*/

#include "INCLUDES.H"

/*
*********************************************************************************************************
*                                             CONSTANTS
*********************************************************************************************************
*/

#define          TASK_STK_SIZE     768                /* Size of each task's stacks (# of bytes)       */
#define          N_TASKS            62                /* Number of identical tasks                     */

/*
*********************************************************************************************************
*                                             VARIABLES
*********************************************************************************************************
*/

UBYTE            TaskStk[N_TASKS][TASK_STK_SIZE];     /* Tasks stacks                                  */
UBYTE            StatStk[TASK_STK_SIZE];
char             TaskData[N_TASKS];                   /* Parameters to pass to each task               */
UBYTE            StatData;
OS_EVENT        *RandomSem;	  
UWORD            OldSS;
UWORD            OldSP;
UWORD            OldBP;
void interrupt (*OldTickISR)(void);

/*
*********************************************************************************************************
*                                         FUNCTION PROTOTYPES
*********************************************************************************************************
*/

void far         Task(void *data);                    /* Function prototypes of tasks                  */
void far         Stat(void *data);                    /* Function prototypes of Statistics task        */
void             DispChar(UBYTE x, UBYTE y, char c);
void             DispStr(UBYTE x, UBYTE y, char *s);

/*$PAGE*/
/*
*********************************************************************************************************
*                                                  MAIN
*********************************************************************************************************
*/

void main(void)
{
    clrscr();                                              /* Clear the screen                         */
    OldBP      = _BP;                                      /* Save current SS, SP and BP               */
	OldSS      = _SS;
    OldSP      = _SP;
    OldTickISR = getvect(0x08);                            /* Get MS-DOS's tick vector                 */
    setvect(0x81, OldTickISR);                             /* Store MS-DOS's tick to chain             */
    setvect(uCOS, (void interrupt (*)(void))OSCtxSw);      /* uC/OS's context switch vector            */
    OSInit();
    RandomSem = OSSemCreate(1);                            /* Random number semaphore                  */
    OSTaskCreate(Stat, (void *)&StatData, (void *)&StatStk[TASK_STK_SIZE], 62);
    OSStart();                                             /* Start multitasking                       */
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                              STATISTICS TASK
*********************************************************************************************************
*/

void far Stat(void *data)
{
    UBYTE  i;
    char   s[100];
    double max;
    double usage;


    data = data;                                           /* Prevent compiler warning                 */
    OS_ENTER_CRITICAL();
    setvect(0x08, (void interrupt (*)(void))OSTickISR);    /* Install uC/OS's clock tick ISR           */
    OS_EXIT_CRITICAL();
    DispStr(0, 22, "Determining  CPU's capacity ...");     /* Determine maximum count for OSIdleCtr    */
    OSTimeDly(1);                                          /* Synchronize to clock tick                */
    OSIdleCtr = 0L;                                        /* Determine MAX. idle counter value ...    */
    OSTimeDly(18);                                         /* ... for 18 clock ticks                   */
    max       = (double)OSIdleCtr;
    for (i = 0; i < N_TASKS; i++) {                        /* Create N_TASKS identical tasks           */
        TaskData[i] = ' ' + i;
        OSTaskCreate(Task, (void *)&TaskData[i], (void *)&TaskStk[i][TASK_STK_SIZE], i);
    }
    DispStr(0, 23, "Press any key to quit.");
    OSIdleCtr = 0L;
    while (1) {
        usage = 100.0 - (100.0 * (double)OSIdleCtr / max); /* Compute and display statistics           */
        sprintf(s, "Task Switches/sec: %d   CPU Usage: %5.2f %%   Idle Ctr: %7.0f / %7.0f   ",
                OSCtxSwCtr,
                usage,
                (double)OSIdleCtr,
                max);
        DispStr(0, 22, s);
        if (kbhit()) {                                     /* Exit if any key pressed                  */
            OS_ENTER_CRITICAL();
            setvect(0x08, OldTickISR);
            OS_EXIT_CRITICAL();
            clrscr();
            _BP = OldBP;                                   /* Restore old SP and BP                    */
			_SS = OldSS;
            _SP = OldSP;
            exit(0);
        }
        OS_ENTER_CRITICAL();
        OSCtxSwCtr = 0;                                    /* Reset statistics counters                */
        OSIdleCtr  = 0L;
        OS_EXIT_CRITICAL();
        OSTimeDly(18);                                     /* Wait one second                          */
    }
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                                  TASKS
*********************************************************************************************************
*/

void far Task(void *data)
{
    UBYTE x;
    UBYTE y;
    UBYTE err;


    while (1) {
        OSTimeDly(1);                            /* Delay 1 clock tick                                 */
        OSSemPend(RandomSem, 0, &err);           /* Acquire semaphore to perform random numbers        */
        x = random(79);                          /* Find X position where task number will appear      */
        y = random(21);                          /* Find Y position where task number will appear      */
        OSSemPost(RandomSem);                    /* Release semaphore                                  */
        DispChar(x, y, *(char *)data);           /* Display the task number on the screen              */
    }
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                                DISPLAY FUNCTIONS
*********************************************************************************************************
*/
void DispChar(UBYTE x, UBYTE y, char c)
{
    UBYTE far *pscr;
    UWORD      offset;


    offset  = (UWORD)y * 160 + (UWORD)x * 2;     /* Calculate position of character on the screen      */
    pscr    = MK_FP(0xB800, offset);
    OS_ENTER_CRITICAL();
    *pscr++ = c;                                 /* Put character in video RAM                         */
    *pscr   = 0x07;                              /* Put video attribute in video RAM                   */
    OS_EXIT_CRITICAL();
}



void DispStr(UBYTE x, UBYTE y, char *s)
{
    UBYTE far *pscr;
    UWORD      offset;


    offset  = (UWORD)y * 160 + (UWORD)x * 2;     /* Calculate position of character on the screen      */
    pscr    = MK_FP(0xB800, offset);
    while (*s) {
        OS_ENTER_CRITICAL();
        *pscr++ = *s++;                          /* Put character in video RAM                         */
        *pscr++ = 0x07;                          /* Put video attribute in video RAM                   */
        OS_EXIT_CRITICAL();
    }
}
